#-*- coding:Utf-8 -*-

""" reseaux --->  Ce module permet d’initialiser le réseaux des capteurs sans fil, de préciser la position des capteurs et des agrégateurs, et enfin la répartition des capteurs sur des agrégateurs ou sur des autres capteurs (qui dépend de la topologie utilisée)  """

#import rsa
from networkx import *
from time import time
from random import randint, gauss
from os import system, listdir
from math import sqrt
from puits import Puits
from agregateur import Agregateur
from capteur import Capteur
from donnees import *
from fonction import *

# Nettoyage
if 'data' not in listdir('.'):
    system('mkdir -p data/topologies')
    system('mkdir -p data/DataForet')
    system('mkdir -p data/Décision')
else:
    system('rm data/topologies/*')
    system('rm data/DataForet/*')
    system('rm data/Décision/*')

if not SIR :
    if 'tmp' not in listdir('.'):
        system('mkdir tmp')
    else:
        system('rm tmp/*')

    if 'foret' not in listdir('.'):
        system('mkdir foret')
    else:
        system('rm foret/*')    

    data = Genere_Data(individus)
    fic = open('data/DataForet/donnees_apprentissage.txt','w')
    fic.write(str(data))
    fic.close()


    print "Répartition des données au sein des diverses catégories d'usure : "
    print [[Quelle_Categorie(k) for k in data].count(u) for u in range(nbCategories)]

    for k in range(nbArbre):
        echantillon = Extrait_Echantillon(data)
        G=DiGraph()
        n=[-1,-2,-3,-4,-5]
        root = [Quelle_Categorie(v) for v in echantillon]
        root = [root.count(v) for v in range(nbCategories)]
        L = [tuple(root)]  
        categor = Categories.keys()
        echantillons = {}
        echantillons[tuple(root)] = echantillon
        while len(L) > 0:
            X = Fils_De(echantillons[L[0]], G, L[0], tuple(root))
            if X != None:
                aRetenir, noeuds, nouveauxEchantillons = X
                G.add_node(L[0])
                for item,noeud in enumerate(noeuds):
                    if noeud != tuple([0]*nbCategories):
                        G.add_node(noeud)
                        G.add_edge(L[0],noeud, label=aRetenir+'_'+str(item))
                    elif noeud == tuple([0]*nbCategories):
                        G.add_node(n[item])
                        G.add_edge(L[0],n[item], label=aRetenir+'_'+str(item))
                
                    if noeud.count(0) < nbCategories-1:
                        L.append(noeud)
                        echantillons[noeud] = nouveauxEchantillons[item]
            del L[0]
        foret.append((G,tuple(root)))

    for item,(G,racine) in enumerate(foret):
        write_dot(G,'data/DataForet/graphe_'+str(item)+'.dot')
        system("dot data/DataForet/graphe_"+str(item)+".dot -T png > foret/graphe_"+str(item)+".png")

    print "Nombre d'arbres dans la forêt :  ",nbArbre


if Topologie==1 and not SIR:
    if choixNbAgregateurs == 3:
        print("Nombre d'agrégateurs fixé par l'utilisateur")
    elif choixNbAgregateurs == 2:
        print("Tirage uniforme du nombre d'agrégateurs")
        AgregateursMax = input("Combien d'agrégateurs au maximum ? ")
        AgregateursTotaux = randint(1,AgregateursMax)
        print("Valeur maxi du tirage uniforme du nombre d'agregateurs "+str(AgregateursTotaux))
    else:
        print("Tirage gaussien du nombre d'agrégateurs")
        AgregateursMoyen = input("Combien d'agrégateurs en moyenne ? ")
        AgregateursEcart = input("Ecart-type ? ")
        print("Valeur moyenne du tirage gaussien d'agrégateurs : "+str(AgregateursMoyen))
        print("Ecart-type du tirage gaussien d'agrégateurs : "+str(AgregateursEcart))
        AgregateursTotaux = int(gauss(AgregateursMoyen,AgregateursEcart))
        while AgregateursTotaux <= 0:
            AgregateursTotaux = int(gauss(AgregateursMoyen,AgregateursEcart))

    print("Nombre d'agregateurs totaux : "+str(AgregateursTotaux))


if choixNbCapteurs == 3:
    print("Nombre de capteurs fixé par l'utilisateur")
elif choixNbCapteurs == 2:
    print("Tirage uniforme du nombre de capteurs")
    CapteursMax = input("Combien de capteurs au maximum ? ")
    CapteursTotaux = randint(1,CapteursMax)
    print("Valeur maxi du tirage uniforme du nombre de capteurs "+str(CapteursTotaux))
else:
    print("Tirage gaussien du nombre de capteurs")
    CapteursMoyen = input("Combien de capteurs en moyenne ? ")
    CapteursEcart = input("Ecart-type ? ")
    print("Valeur moyenne du tirage gaussien de capteurs : "+str(CapteursMoyen))
    print("Ecart-type du tirage gaussien de capteurs : "+str(CapteursEcart))     
    CapteursTotaux = int(gauss(CapteursMoyen,CapteursEcart))
    while CapteursTotaux <= 0:
        CapteursTotaux = int(gauss(CapteursMoyen,CapteursEcart))

print("Nombre des capteurs totaux : "+str(CapteursTotaux))

if not SIR :
    if choixNbCapteurs == 3:
        CapteurTemperature = Categ['temperature']
        print "Le nombre de capteurs de temperature est {} :".format(CapteurTemperature)

        CapteurPressure = Categ['pressure']
        print "Le nombre de capteurs de pressure est {} :".format(CapteurPressure)
      
        CapteurHumidity = Categ['humidity']
        print "Le nombre de capteurs d'humidity est {} :".format(CapteurHumidity)

    elif CapteursTotaux % len(Categ.keys()) == 0 :
        CapteurTemperature = CapteursTotaux/len(Categ.keys())
        print "Le nombre de capteurs de temperature est {} :".format(CapteurTemperature)
    
        CapteurPressure = CapteursTotaux/len(Categ.keys())
        print "Le nombre de capteurs de pressure est {} :".format(CapteurPressure) 

        CapteurHumidity = CapteursTotaux/len(Categ.keys())
        print "Le nombre de capteurs d'humidity est {} :".format(CapteurHumidity)

    elif CapteursTotaux % len(Categ.keys()) == 1 :
        CapteurTemperature = CapteursTotaux/len(Categ.keys()) + 1
        print "Le nombre de capteurs de temperature est {} :".format(CapteurTemperature)
    
        CapteurPressure = CapteursTotaux/len(Categ.keys())
        print "Le nombre de capteurs de pressure est {} :".format(CapteurPressure) 

        CapteurHumidity = CapteursTotaux/len(Categ.keys())
        print "Le nombre de capteurs d'humidity est {} :".format(CapteurHumidity)   

    elif CapteursTotaux % len(Categ.keys()) == 2 :
        CapteurTemperature = CapteursTotaux/len(Categ.keys()) + 1
        print "Le nombre de capteurs de temperature est {} :".format(CapteurTemperature)
    
        CapteurPressure = CapteursTotaux/len(Categ.keys()) + 1
        print "Le nombre de capteurs de pressure est {} :".format(CapteurPressure) 

        CapteurHumidity = CapteursTotaux/len(Categ.keys())
        print "Le nombre de capteurs d'humidity est {} :".format(CapteurHumidity)   


Puits = Puits(foret)

if CHIFFREMENT:
    Kp = Puits.Kp
    Ks = Puits.Ks
else:
    Kp, Ks = None, None

if Topologie == 1 and not SIR:

    for k in range(AgregateursTotaux):
        Puits.agregateurs.append(Agregateur(numero = k, Kp = Kp, Ks = Ks, puits = Puits))

cp = 0

if not SIR:
    #cree les capteurs de different categories
    for j in Categ.keys():
        for a in range(Categ[j]):
            Puits.dicoCapteurs[cp] = Capteur(numero = cp, Kp = Kp, puits = Puits, Categorie = j)
            cp += 1
elif SIR :
    #cree les capteurs
    for j in range(CapteursTotaux):
        Puits.dicoCapteurs[j] = Capteur(numero = j, Kp = Kp, puits = Puits)      

if DistributionCapteurs == 1:
    # Si la distribution des capteurs est aléatoires
    pass
elif DistributionCapteurs == 2:
    # Sinon, elle est suivant une grille, et le nombre de capteurs doit être un carré
    try:
        assert CapteursTotaux == int(sqrt(CapteursTotaux)**2)
    except:
        print "Erreur : le nombre de capteurs doit être un carré pour les répartir sur une grille"
        exit()
    cpt = 0
    for X in range(int(sqrt(CapteursTotaux))):
        for Y in range(int(sqrt(CapteursTotaux))):
            Puits.dicoCapteurs[cpt].x = float(X)/int(sqrt(CapteursTotaux))+1./(2*int(sqrt(CapteursTotaux)))
            Puits.dicoCapteurs[cpt].y = float(Y)/int(sqrt(CapteursTotaux))+1./(2*int(sqrt(CapteursTotaux)))            
            cpt += 1
if Topologie == 1 and not SIR:

    if DistributionAgregateurs == 1:
    # Distribution des agrégateurs aléatoire
        if choixRepartition == 1:
            # On répartit aléatoirement les capteurs sur les agrégateurs
            for cap in range(CapteursTotaux):
                ag = randint(0,AgregateursTotaux-1)
                Puits.agregateurs[ag].capteurs.append(Puits.dicoCapteurs[cap])
                Puits.dicoCapteurs[cap].agregateur = Puits.agregateurs[ag]
        elif choixRepartition == 2:
            print "Kmean impossible quand les agrégateurs sont répartis aléatoirement"
            exit()
        elif choixRepartition == 3:
            # Les capteurs sont connectés à leurs plus proches agrégateurs
            for i in range(CapteursTotaux):
                distance = sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[0].x)**2+(Puits.dicoCapteurs[i].y-Puits.agregateurs[0].y)**2)
                Puits.dicoCapteurs[i].agregateur = Puits.agregateurs[0]
                for j in range(1,AgregateursTotaux):
                    if distance > sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[j].x)**2+(Puits.dicoCapteurs[i].y-Puits.agregateurs[j].y)**2):
                        Puits.dicoCapteurs[i].agregateur = Puits.agregateurs[j]
                        distance = sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[j].x)**2+(Puits.dicoCapteurs[i].y-Puits.agregateurs[j].y)**2)
                Puits.agregateurs[Puits.dicoCapteurs[i].agregateur.numero].capteurs.append(Puits.dicoCapteurs[i])
    elif DistributionAgregateurs == 2:
        # Les agrégateurs sont répartis sur une grille, et le nombre d'agrégateurs doit être un carré
        try:
            assert AgregateursTotaux == int(sqrt(AgregateursTotaux)**2)
        except:
            print "Erreur : le nombre d'agrégateurs doit être un carré pour les répartir sur une grille"
            exit()
        cpt = 0
        for X in range(int(sqrt(AgregateursTotaux))):
            for Y in range(int(sqrt(AgregateursTotaux))):
                Puits.agregateurs[cpt].x = float(X)/int(sqrt(AgregateursTotaux)) + 1./(2*int(sqrt(AgregateursTotaux)))
                Puits.agregateurs[cpt].y = float(Y)/int(sqrt(AgregateursTotaux)) + 1./(2*int(sqrt(AgregateursTotaux)))            
                cpt += 1    
        # On répartit maintenant les capteurs sur les agrégateurs
        if choixRepartition == 1:
            # On répartit aléatoirement les capteurs sur les agrégateurs
            for cap in range(CapteursTotaux):
                ag = randint(0,AgregateursTotaux-1)
                Puits.agregateurs[ag].capteurs.append(Puits.dicoCapteurs[cap])
                #ajoute ce ligne dans choixRepartition==1
                Puits.dicoCapteurs[cap].agregateur = Puits.agregateurs[ag]
        elif choixRepartition == 2:
            print "Kmean impossible quand les agrégateurs sont répartis sur une grille"
            exit()
        elif choixRepartition == 3:
            # Les capteurs sont connectés à leurs plus proches agrégateurs
            for i in range(CapteursTotaux):
                distance = sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[0].x)**2 + (Puits.dicoCapteurs[i].y-Puits.agregateurs[0].y)**2)
                Puits.dicoCapteurs[i].agregateur = Puits.agregateurs[0]
                for j in range(1,AgregateursTotaux):
                    if distance > sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[j].x)**2 + (Puits.dicoCapteurs[i].y-Puits.agregateurs[j].y)**2):
                        Puits.dicoCapteurs[i].agregateur = Puits.agregateurs[j]
                        distance = sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[j].x)**2 + (Puits.dicoCapteurs[i].y-Puits.agregateurs[j].y)**2)
                Puits.agregateurs[Puits.dicoCapteurs[i].agregateur.numero].capteurs.append(Puits.dicoCapteurs[i])
    elif DistributionAgregateurs == 3:
        # On passe au k-mean
        listeInitialeBarycentres = []
        for k in range(AgregateursTotaux):
            listeInitialeBarycentres.append((Puits.agregateurs[k].x,Puits.agregateurs[k].y))
        while True:
            listeBarycentres = []
            # Les capteurs sont connectés à leurs plus proches agrégateurs
            for ag in range(AgregateursTotaux):
                Puits.agregateurs[ag].capteurs = []
            for i in range(CapteursTotaux):
                distance = sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[0].x)**2 + (Puits.dicoCapteurs[i].y-Puits.agregateurs[0].y)**2)
                Puits.dicoCapteurs[i].agregateur = Puits.agregateurs[0]
                for j in range(1,AgregateursTotaux):
                    if distance > sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[j].x)**2 + (Puits.dicoCapteurs[i].y-Puits.agregateurs[j].y)**2):
                        Puits.dicoCapteurs[i].agregateur = Puits.agregateurs[j]
                        distance = sqrt((Puits.dicoCapteurs[i].x-Puits.agregateurs[j].x)**2 + (Puits.dicoCapteurs[i].y-Puits.agregateurs[j].y)**2)
                Puits.agregateurs[Puits.dicoCapteurs[i].agregateur.numero].capteurs.append(Puits.dicoCapteurs[i])        
            for k in range(AgregateursTotaux):
                try:
                    Puits.agregateurs[k].x = float(sum([Puits.dicoCapteurs[cap.numero].x for cap in Puits.agregateurs[k].capteurs]))/len(Puits.agregateurs[k].capteurs)
                    Puits.agregateurs[k].y = float(sum([Puits.dicoCapteurs[cap.numero].y for cap in Puits.agregateurs[k].capteurs]))/len(Puits.agregateurs[k].capteurs)
                except:
                    pass
            for k in range(AgregateursTotaux):
                listeBarycentres.append((Puits.agregateurs[k].x,Puits.agregateurs[k].y))
            if listeBarycentres == listeInitialeBarycentres:
                break
            else:
                listeInitialeBarycentres = listeBarycentres

    # Nous précisons l'agrégateur cible pour chaque agrégateur

    if not DIRECT_AGREGATEUR_PUITS:
        for agr in Puits.agregateurs:
            ordre = sorted(Puits.agregateurs, key=lambda k: sqrt((k.x-agr.x)**2 + (k.y-agr.y)**2))
            agr.agregateurCible = Puits

            for ag in ordre:
                if sqrt((ag.x-Puits.x)**2 + (ag.y-Puits.y)**2) < sqrt((agr.x-Puits.x)**2 + (agr.y-Puits.y)**2):
                    agr.agregateurCible = ag
                    break        

elif Topologie == 2 and not SIR :

    if not DIRECT_CAPTEUR_PUITS :

        for capteur in Puits.dicoCapteurs.values() :
            orde = sorted(Puits.dicoCapteurs.values(), key=lambda k: sqrt((k.x-capteur.x)**2 + (k.y-capteur.y)**2))

            ordre = [C for C in orde if  sqrt((C.x-capteur.x)**2 + (C.y-capteur.y)**2) <= Range ]

            capteur.capteurCible = Puits
           
            for cp in ordre:
                if sqrt((cp.x-Puits.x)**2 + (cp.y-Puits.y)**2) < sqrt((capteur.x-Puits.x)**2 + (capteur.y-Puits.y)**2):
                    capteur.capteurCible = cp
                    break   
    else :

        for capteur in Puits.dicoCapteurs.values() :
            orde = sorted(Puits.dicoCapteurs.values(), key=lambda k: sqrt((k.x-capteur.x)**2 + (k.y-capteur.y)**2))

            ordre = [C for C in orde if  sqrt((C.x-capteur.x)**2 + (C.y-capteur.y)**2) <= Range ]

            distance = sqrt((capteur.x-Puits.x)**2 + (capteur.y-Puits.y)**2)

            capteur.capteurCible = Puits

            for cp in range(len(ordre)) :
                if distance > sqrt((ordre[cp].x-Puits.x)**2 + (ordre[cp].y-Puits.y)**2) :
                    distance =  sqrt((ordre[cp].x-Puits.x)**2 + (ordre[cp].y-Puits.y)**2) 
                    capteur.capteurCible = ordre[cp]

            
elif SIR :

     # metter la cible de tous les capteurs est le puits
     for capteur in Puits.dicoCapteurs.values() :
         capteur.capteurCible = Puits
                

print "Fin l'initialisation du réseau"  

for k in Categories.keys():
    assert len(Categories[k]['limites']) == nbCategories-1


Puits.Run()    
